#include "xlcomm/net/inet_address.h"

#include <arpa/inet.h>

#include "xlcomm/base/logger.h"
#include "xlcomm/net/endian.h"

namespace xlcomm {
namespace net {

InetAddress::InetAddress() { MemZero(&addrin_, sizeof addrin_); }

InetAddress::InetAddress(uint16_t port, const char* ip) {
  MemZero(&addrin_, sizeof addrin_);
  addrin_.sin_family = AF_INET;
  addrin_.sin_port = HostToNetwork16(port);
  if (ip == nullptr) {
    addrin_.sin_addr.s_addr = INADDR_ANY;
  } else if (inet_pton(AF_INET, ip, &addrin_.sin_addr) <= 0) {
    LOG_FATAL << "inet_pton() error! please check ip:" << ip;
  }
}

InetAddress::InetAddress(const struct sockaddr& addr) { FromSockaddr(addr); }

InetAddress::~InetAddress() {}

void InetAddress::SetSockaddrIn(const struct sockaddr_in& addrin) {
  addrin_ = addrin;
}

void InetAddress::FromSockaddr(const struct sockaddr& addr) {
  memcpy(&addrin_, &addr, sizeof(addr));
}

const struct sockaddr* InetAddress::ToSockaddr() const {
  return reinterpret_cast<const struct sockaddr*>(&addrin_);
}

std::string InetAddress::ToIp() const {
  char buff[32];
  if (inet_ntop(AF_INET, &addrin_.sin_addr, buff, sizeof(buff)) == nullptr) {
    LOG_SYSFATAL(inet_ntop);
  }
  return buff;
}

std::string InetAddress::ToIpPort() const {
  uint16_t port = Port();
  char buff[64];
  snprintf(buff, sizeof(buff), "%s:%u", ToIp().c_str(), port);
  return buff;
}

uint16_t InetAddress::Port() const { return NetworkToHost16(addrin_.sin_port); }

}  // namespace net
}  // namespace xlcomm